<!DOCTYPE HTML>
<html>
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">

    

    <title>OkHttp使用教程 | uuxia</title>
    <meta name="author" content="uuxia">
    
    <meta name="description" content="在浮躁的世界安安静静地敲代码">
    
    
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">

    <meta property="og:title" content="OkHttp使用教程"/>
    <meta property="og:site_name" content="uuxia的技术博客"/>

    
    <meta property="og:image" content=""/>
    

    <link rel="icon" type="image/png" href="/favicon.png">
    <link rel="alternate" href="/atom.xml" title="uuxia的技术博客" type="application/atom+xml">
    <link rel="stylesheet" href="/css/lib/materialize.min.css">
    <link rel="stylesheet" href="/css/lib/font-awesome.min.css">
    <link rel="stylesheet" href="/css/style.css" media="screen" type="text/css">

    
        <link rel="stylesheet" href="/css/lib/prettify-tomorrow-night-eighties.css" type="text/css">
    
    <!--[if lt IE 9]><script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script><![endif]-->
</head>


<body>
    <img src="/weixin_favicon.png" style="position: absolute; left: -9999px; opacity: 0; filter: alpha(opacity=0);">

    <nav class="indigo">
    <div class="nav-wrapper">
        <a href="#" data-activates="main-menu" class="button-collapse">
            <i class="fa fa-navicon"></i>
        </a>
        <div class="">
            <a href="/" class="brand-logo hide-on-med-and-down">uuxia的技术博客</a>
            <ul class="right hide-on-med-and-down">
                
                    <li>
                        <a class="menu-home " href="/" >
                            <i class="fa fa-home "></i>
                            
                            首页
                        </a>
                    </li>
                
                    <li>
                        <a class="menu-archive " href="/archives" >
                            <i class="fa fa-archive "></i>
                            
                            归档
                        </a>
                    </li>
                
                    <li>
                        <a class="menu-category category-menu" href="javascript:;" data-activates="category-menu" >
                            <i class="fa fa-bookmark "></i>
                            
                            分类
                        </a>
                    </li>
                
                    <li>
                        <a class="menu-reading " href="/reading" >
                            <i class="fa fa-book "></i>
                            
                            读书
                        </a>
                    </li>
                
                    <li>
                        <a class="menu-about " href="/about" >
                            <i class="fa fa-user "></i>
                            
                            关于
                        </a>
                    </li>
                
                    <li>
                        <a class="menu-search modal-trigger " href="#search" >
                            <i class="fa fa-search "></i>
                            
                            搜索
                        </a>
                    </li>
                
            </ul>
            <div>
    <ul class="side-nav indigo darken-1" id="main-menu">
        
        <li class="side-user">
            <div class="row">
                <div class="col s4 no-padding">
                    <img class="avatar-image circle responsive-img" src="http://uuxia.cn/image/icon.png" alt="User Avatar">
                </div>
                <div class="info col s8 valign-wrapper no-padding">
                    <div class="valign">
                        <p class="name">uuxia</p>
                        <p class="desc">前端/Android/Java/C++/技术宅</p>
                    </div>
                </div>
            </div>
        </li>
        

        
            <li class="no-padding">
                <a class="waves-effect menu-home " href="/" >
                    <i class="fa fa-home "></i>
                    
                    首页
                </a>
            </li>
        
            <li class="no-padding">
                <a class="waves-effect menu-archive " href="/archives" >
                    <i class="fa fa-archive "></i>
                    
                    归档
                </a>
            </li>
        
            <li class="no-padding">
                <a class="waves-effect menu-category category-menu" href="javascript:;" data-activates="category-menu" >
                    <i class="fa fa-bookmark "></i>
                    
                    分类
                </a>
            </li>
        
            <li class="no-padding">
                <a class="waves-effect menu-reading " href="/reading" >
                    <i class="fa fa-book "></i>
                    
                    读书
                </a>
            </li>
        
            <li class="no-padding">
                <a class="waves-effect menu-about " href="/about" >
                    <i class="fa fa-user "></i>
                    
                    关于
                </a>
            </li>
        
            <li class="no-padding">
                <a class="waves-effect menu-search modal-trigger " href="#search" >
                    <i class="fa fa-search "></i>
                    
                    搜索
                </a>
            </li>
        
    </ul>

    <ul class="side-nav indigo darken-1" id="category-menu">
    

            

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/翻墙/">
                    翻墙 <span class="right">2 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/NDK/">
                    NDK <span class="right">1 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/vpn/">
                    vpn <span class="right">1 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/Java/">
                    Java <span class="right">1 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/Service/">
                    Service <span class="right">1 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/生活/">
                    生活 <span class="right">3 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/IoT/">
                    IoT <span class="right">1 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/ios/">
                    ios <span class="right">1 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/android/">
                    android <span class="right">1 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/智能家居/">
                    智能家居 <span class="right">2 篇</span></a>
                </a>
            </li>

        

            <li class="collapse-level-0" collapse-level="0">
                <a class="no-padding" href="/categories/迅雷/">
                    迅雷 <span class="right">1 篇</span></a>
                </a>
            </li>

        

    </ul>
</div>

        </div>
    </div>
</nav>

<div id="search" class="modal search-modal">
    <div class="row">
        <div class="input-field col s12">
              <input id="search-input" type="text">
              <label for="search-input">搜索</label>
        </div>

    </div>
    <div id="search-result" class="search-result col s12">

    </div>
</div>


    <main>
        <!--add by uuxia 20180402 内容页面的宽度改变-->
<div class="container main-container1">
    <nav class="page-nav hide-on-small-only">
    <div class="nav-wrapper indigo">
        <span class="breadcrumb">当前位置（分类目录）</span>
        
            
    
    
    <a class="breadcrumb" href="/categories/android/">android</a>


        

        
    </div>
</nav>

<article>
    <div class="card">
        <div class="card-content">
            

            <div class="article-title">
                
    
        <h1>OkHttp使用教程</h1>
    


            </div>
            <time class="pink-link-context" datetime="2016-05-09T23:29:13.000Z"><a href="/2016/05/09/okhttphelp/">2016-05-09</a></time>

            <span id="busuanzi_container_page_pv" class="read-times-container">
    <i class="fa fa-eye"></i>
    <span id="busuanzi_value_page_pv"></span>
</span>

            
    <div class="tags-row">
        
            <a href="/tags/okhttp/" class="chip pink lighten-1">okhttp</a>
        
            <a href="/tags/android/" class="chip pink lighten-1">android</a>
        
    </div>


            <div class="toc pink-link-context hide-on-med-and-down">
    <ol class="section table-of-contents"><li class="section table-of-contents-item section table-of-contents-level-1"><a class="section table-of-contents-link" href="#入门"><span class="section table-of-contents-text">入门</span></a><ol class="section table-of-contents-child"><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#官方资料"><span class="section table-of-contents-text">官方资料</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#使用范围"><span class="section table-of-contents-text">使用范围</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#jar包准备"><span class="section table-of-contents-text">jar包准备</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#基本使用"><span class="section table-of-contents-text">基本使用</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#总结"><span class="section table-of-contents-text">总结</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#高级"><span class="section table-of-contents-text">高级</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#同步get"><span class="section table-of-contents-text">同步get</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#异步get"><span class="section table-of-contents-text">异步get</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#提取响应头"><span class="section table-of-contents-text">提取响应头</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#Post方式提交String"><span class="section table-of-contents-text">Post方式提交String</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#Post方式提交流"><span class="section table-of-contents-text">Post方式提交流</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#Post方式提交文件"><span class="section table-of-contents-text">Post方式提交文件</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#Post方式提交表单"><span class="section table-of-contents-text">Post方式提交表单</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#Post方式提交分块请求"><span class="section table-of-contents-text">Post方式提交分块请求</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#使用Gson来解析JSON响应"><span class="section table-of-contents-text">使用Gson来解析JSON响应</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#响应缓存"><span class="section table-of-contents-text">响应缓存</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#扩展"><span class="section table-of-contents-text">扩展</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#Force-a-Network-Response"><span class="section table-of-contents-text">Force a Network Response</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#取消一个Call"><span class="section table-of-contents-text">取消一个Call</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#超时"><span class="section table-of-contents-text">超时</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#每个call的配置"><span class="section table-of-contents-text">每个call的配置</span></a></li><li class="section table-of-contents-item section table-of-contents-level-2"><a class="section table-of-contents-link" href="#处理验证"><span class="section table-of-contents-text">处理验证</span></a></li></ol></li></ol>
</div>


            <div class="entry pink-link-context">
                <p>这是一个针对技术开发者的一个应用，你可以在掘金上获取最新最优质的技术干货，不仅仅是Android知识、前端、后端以至于产品和设计都有涉猎，想成为全栈工程师的朋友不要错过！<br><a id="more"></a></p>
<h1 id="入门"><a href="#入门" class="headerlink" title="入门"></a>入门</h1><p>Android系统提供了两种HTTP通信类，HttpURLConnection和HttpClient。<br><a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html" target="_blank" rel="noopener">关于HttpURLConnection和HttpClient的选择&gt;&gt;官方博客</a><br>尽管Google在大部分安卓版本中推荐使用HttpURLConnection，但是这个类相比HttpClient实在是太难用，太弱爆了。<br>OkHttp是一个相对成熟的解决方案，据说Android4.4的源码中可以看到HttpURLConnection已经替换成OkHttp实现了。所以我们更有理由相信OkHttp的强大。</p>
<p>OkHttp 处理了很多网络疑难杂症：会从很多常用的连接问题中自动恢复。如果您的服务器配置了多个IP地址，当第一个IP连接失败的时候，OkHttp会自动尝试下一个IP。OkHttp还处理了代理服务器问题和SSL握手失败问题。</p>
<p>使用 OkHttp 无需重写您程序中的网络代码。OkHttp实现了几乎和java.net.HttpURLConnection一样的API。如果你用了 Apache HttpClient，则OkHttp也提供了一个对应的okhttp-apache 模块。</p>
<blockquote>
<p>注：在国内使用OkHttp会因为这个问题导致部分酷派手机用户无法联网，所以对于大众app来说，需要等待这个bug修复后再使用。或者尝试使用OkHttp的老版本。<br>截止到目前，OkHttp一直没有修复，并把修复计划延迟到了OkHttp2.3中。不是所有设备都能重现，仅少量设备会出现这个问题。（如果问题这么明显，OkHttp早就修复了）</p>
</blockquote>
<h2 id="官方资料"><a href="#官方资料" class="headerlink" title="官方资料"></a>官方资料</h2><p><a href="http://square.github.io/okhttp/" target="_blank" rel="noopener">官方介绍</a><br><a href="https://github.com/square/okhttp" target="_blank" rel="noopener">github源码</a></p>
<h2 id="使用范围"><a href="#使用范围" class="headerlink" title="使用范围"></a>使用范围</h2><p>OkHttp支持Android 2.3及其以上版本。<br>对于Java, JDK1.7以上。</p>
<h2 id="jar包准备"><a href="#jar包准备" class="headerlink" title="jar包准备"></a>jar包准备</h2><p>官方介绍页面有链接位置。这里把下载链接也写在下面。<br><a href="http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&amp;g=com.squareup.okhttp&amp;a=okhttp&amp;v=LATEST" target="_blank" rel="noopener">OkHttp</a><br><a href="http://repository.sonatype.org/service/local/artifact/maven/redirect?r=central-proxy&amp;g=com.squareup.okio&amp;a=okio&amp;v=LATEST" target="_blank" rel="noopener">Okio</a></p>
<h2 id="基本使用"><a href="#基本使用" class="headerlink" title="基本使用"></a>基本使用</h2><p><strong>HTTP GET</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">OkHttpClient client = new OkHttpClient();</span><br><span class="line"> </span><br><span class="line">String run(String url) throws IOException &#123;</span><br><span class="line">    Request request = new Request.Builder().url(url).build();</span><br><span class="line">    Response response = client.newCall(request).execute();    if (response.isSuccessful()) &#123;        return response.body().string();</span><br><span class="line">    &#125; else &#123;        throw new IOException(&quot;Unexpected code &quot; + response);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>Request是OkHttp中访问的请求，Builder是辅助类。Response即OkHttp中的响应。<br><strong>Response类：</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">public boolean isSuccessful()</span><br><span class="line">Returns true if the code is in [200..300),</span><br><span class="line"> which means the request was successfully received, understood, and accepted.</span><br></pre></td></tr></table></figure>
<p><strong>response.body()返回ResponseBody类</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">public final String string() throws IOException</span><br><span class="line">Returns the response as a string decoded with the charset of the Content-Type header. If that header is either absent or lacks a charset,</span><br><span class="line"> this will attempt to decode the response body as UTF-8.Throws:</span><br><span class="line">IOException</span><br></pre></td></tr></table></figure>
<p>当然也能获取到流的形式：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">public final InputStream byteStream()</span><br></pre></td></tr></table></figure>
<p><strong>HTTP POST<br>POST提交Json数据</strong></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line">public static final MediaType JSON = MediaType.parse(&quot;application/json; charset=utf-8&quot;);</span><br><span class="line">OkHttpClient client = new OkHttpClient();</span><br><span class="line">String post(String url, String json) throws IOException &#123;</span><br><span class="line">     RequestBody body = RequestBody.create(JSON, json);</span><br><span class="line">      Request request = new Request.Builder()</span><br><span class="line">      .url(url)</span><br><span class="line">      .post(body)</span><br><span class="line">      .build();</span><br><span class="line">      Response response = client.newCall(request).execute();</span><br><span class="line">    f (response.isSuccessful()) &#123;</span><br><span class="line">        return response.body().string();</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        throw new IOException(&quot;Unexpected code &quot; + response);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>使用Request的post方法来提交请求体RequestBody</p>
<p><strong> POST提交键值对</strong><br>很多时候我们会需要通过POST方式把键值对数据传送到服务器。 OkHttp提供了很方便的方式来做这件事情。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line">OkHttpClient client = new OkHttpClient();</span><br><span class="line">String post(String url, String json) throws IOException &#123;</span><br><span class="line"> </span><br><span class="line">     RequestBody formBody = new FormEncodingBuilder()</span><br><span class="line">    .add(&quot;platform&quot;, &quot;android&quot;)</span><br><span class="line">    .add(&quot;name&quot;, &quot;bug&quot;)</span><br><span class="line">    .add(&quot;subject&quot;, &quot;XXXXXXXXXXXXXXX&quot;)</span><br><span class="line">    .build();</span><br><span class="line"> </span><br><span class="line">      Request request = new Request.Builder()</span><br><span class="line">      .url(url)</span><br><span class="line">      .post(body)</span><br><span class="line">      .build();</span><br><span class="line"> </span><br><span class="line">      Response response = client.newCall(request).execute();</span><br><span class="line">    if (response.isSuccessful()) &#123;</span><br><span class="line">        return response.body().string();</span><br><span class="line">    &#125; else &#123;</span><br><span class="line">        throw new IOException(&quot;Unexpected code &quot; + response);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>通过上面的例子我们可以发现，OkHttp在很多时候使用都是很方便的，而且很多代码也有重复，因此特地整理了下面的工具类。<br>注意：</p>
<ul>
<li>OkHttp官方文档并不建议我们创建多个OkHttpClient，因此全局使用一个。 如果有需要，可以使用clone方法，再进行自定义。这点在后面的高级教程里会提到。</li>
<li>enqueue为OkHttp提供的异步方法，入门教程中并没有提到，后面的高级教程里会有解释。</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line">import java.io.IOException;</span><br><span class="line">import java.util.List;</span><br><span class="line">import java.util.concurrent.TimeUnit;</span><br><span class="line">import org.apache.http.client.utils.URLEncodedUtils;</span><br><span class="line">import org.apache.http.message.BasicNameValuePair;</span><br><span class="line">import cn.wiz.sdk.constant.WizConstant;</span><br><span class="line">import com.squareup.okhttp.Callback;</span><br><span class="line">import com.squareup.okhttp.OkHttpClient;</span><br><span class="line">import com.squareup.okhttp.Request;</span><br><span class="line">import com.squareup.okhttp.Response; </span><br><span class="line">  </span><br><span class="line">public class OkHttpUtil &#123;</span><br><span class="line">    private static final OkHttpClient mOkHttpClient = new OkHttpClient();</span><br><span class="line">    static&#123;</span><br><span class="line">        mOkHttpClient.setConnectTimeout(30, TimeUnit.SECONDS);</span><br><span class="line">    &#125;</span><br><span class="line">    /**</span><br><span class="line">     * 该不会开启异步线程。</span><br><span class="line">     * @param request</span><br><span class="line">     * @return</span><br><span class="line">     * @throws IOException</span><br><span class="line">     */</span><br><span class="line">    public static Response execute(Request request) throws IOException&#123;</span><br><span class="line">        return mOkHttpClient.newCall(request).execute();</span><br><span class="line">    &#125;</span><br><span class="line">    /**</span><br><span class="line">     * 开启异步线程访问网络</span><br><span class="line">     * @param request</span><br><span class="line">     * @param responseCallback</span><br><span class="line">     */</span><br><span class="line">    public static void enqueue(Request request, Callback responseCallback)&#123;</span><br><span class="line">        mOkHttpClient.newCall(request).enqueue(responseCallback);</span><br><span class="line">    &#125;</span><br><span class="line">    /**</span><br><span class="line">     * 开启异步线程访问网络, 且不在意返回结果（实现空callback）</span><br><span class="line">     * @param request</span><br><span class="line">     */</span><br><span class="line">    public static void enqueue(Request request)&#123;</span><br><span class="line">        mOkHttpClient.newCall(request).enqueue(new Callback() &#123;</span><br><span class="line">             </span><br><span class="line">            @Override</span><br><span class="line">            public void onResponse(Response arg0) throws IOException &#123;</span><br><span class="line">                 </span><br><span class="line">            &#125;</span><br><span class="line">             </span><br><span class="line">            @Override</span><br><span class="line">            public void onFailure(Request arg0, IOException arg1) &#123;</span><br><span class="line">                 </span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">    &#125;</span><br><span class="line">    public static String getStringFromServer(String url) throws IOException&#123;</span><br><span class="line">        Request request = new Request.Builder().url(url).build();</span><br><span class="line">        Response response = execute(request);</span><br><span class="line">        if (response.isSuccessful()) &#123;</span><br><span class="line">            String responseUrl = response.body().string();</span><br><span class="line">            return responseUrl;</span><br><span class="line">        &#125; else &#123;</span><br><span class="line">            throw new IOException(&quot;Unexpected code &quot; + response);</span><br><span class="line">        &#125;</span><br><span class="line">    &#125;</span><br><span class="line">    private static final String CHARSET_NAME = &quot;UTF-8&quot;;</span><br><span class="line">    /**</span><br><span class="line">     * 这里使用了HttpClinet的API。只是为了方便</span><br><span class="line">     * @param params</span><br><span class="line">     * @return</span><br><span class="line">     */</span><br><span class="line">    public static String formatParams(List&lt;BasicNameValuePair&gt; params)&#123;</span><br><span class="line">        return URLEncodedUtils.format(params, CHARSET_NAME);</span><br><span class="line">    &#125;</span><br><span class="line">    /**</span><br><span class="line">     * 为HttpGet 的 url 方便的添加多个name value 参数。</span><br><span class="line">     * @param url</span><br><span class="line">     * @param params</span><br><span class="line">     * @return</span><br><span class="line">     */</span><br><span class="line">    public static String attachHttpGetParams(String url, List&lt;BasicNameValuePair&gt; params)&#123;</span><br><span class="line">        return url + &quot;?&quot; + formatParams(params);</span><br><span class="line">    &#125;</span><br><span class="line">    /**</span><br><span class="line">     * 为HttpGet 的 url 方便的添加1个name value 参数。</span><br><span class="line">     * @param url</span><br><span class="line">     * @param name</span><br><span class="line">     * @param value</span><br><span class="line">     * @return</span><br><span class="line">     */</span><br><span class="line">    public static String attachHttpGetParam(String url, String name, String value)&#123;</span><br><span class="line">        return url + &quot;?&quot; + name + &quot;=&quot; + value;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="高级"><a href="#高级" class="headerlink" title="高级"></a>高级</h2><p>高级属性其实用的不多，这里主要是对OkHttp github官方教程进行了翻译。</p>
<h2 id="同步get"><a href="#同步get" class="headerlink" title="同步get"></a>同步get</h2><p>下载一个文件，打印他的响应头，以string形式打印响应体。<br>响应体的 string() 方法对于小文档来说十分方便、高效。但是如果响应体太大（超过1MB），应避免适应 string()方法 ，因为他会将把整个文档加载到内存中。<br>对于超过1MB的响应body，应使用流的方式来处理body。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">private final OkHttpClient client = new OkHttpClient();</span><br><span class="line"> </span><br><span class="line">public void run() throws Exception &#123;</span><br><span class="line">    Request request = new Request.Builder()</span><br><span class="line">        .url(&quot;http://publicobject.com/helloworld.txt&quot;)</span><br><span class="line">        .build();</span><br><span class="line"> </span><br><span class="line">    Response response = client.newCall(request).execute();</span><br><span class="line">    if (!response.isSuccessful()) throw new IOException(&quot;Unexpected code &quot; + response);</span><br><span class="line"> </span><br><span class="line">    Headers responseHeaders = response.headers();</span><br><span class="line">    for (int i = 0; i &lt; responseHeaders.size(); i++) &#123;</span><br><span class="line">      System.out.println(responseHeaders.name(i) + &quot;: &quot; + responseHeaders.value(i));</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    System.out.println(response.body().string());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="异步get"><a href="#异步get" class="headerlink" title="异步get"></a>异步get</h2><p>在一个工作线程中下载文件，当响应可读时回调Callback接口。读取响应时会阻塞当前线程。OkHttp现阶段不提供异步api来接收响应体。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">private final OkHttpClient client = new OkHttpClient();</span><br><span class="line"> </span><br><span class="line">public void run() throws Exception &#123;</span><br><span class="line">    Request request = new Request.Builder()</span><br><span class="line">        .url(&quot;http://publicobject.com/helloworld.txt&quot;)</span><br><span class="line">        .build();</span><br><span class="line"> </span><br><span class="line">    client.newCall(request).enqueue(new Callback() &#123;</span><br><span class="line">      @Override public void onFailure(Request request, Throwable throwable) &#123;</span><br><span class="line">        throwable.printStackTrace();</span><br><span class="line">      &#125;</span><br><span class="line"> </span><br><span class="line">      @Override public void onResponse(Response response) throws IOException &#123;</span><br><span class="line">        if (!response.isSuccessful()) throw new IOException(&quot;Unexpected code &quot; + response);</span><br><span class="line"> </span><br><span class="line">        Headers responseHeaders = response.headers();</span><br><span class="line">        for (int i = 0; i &lt; responseHeaders.size(); i++) &#123;</span><br><span class="line">          System.out.println(responseHeaders.name(i) + &quot;: &quot; + responseHeaders.value(i));</span><br><span class="line">        &#125;</span><br><span class="line"> </span><br><span class="line">        System.out.println(response.body().string());</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="提取响应头"><a href="#提取响应头" class="headerlink" title="提取响应头"></a>提取响应头</h2><p>典型的HTTP头 像是一个 Map&lt;String, String&gt; :每个字段都有一个或没有值。但是一些头允许多个值，像Guava的Multimap。例如：HTTP响应里面提供的Vary响应头，就是多值的。OkHttp的api试图让这些情况都适用。<br>当写请求头的时候，使用header(name, value)可以设置唯一的name、value。如果已经有值，旧的将被移除，然后添加新的。使用addHeader(name, value)可以添加多值（添加，不移除已有的）。<br>当读取响应头时，使用header(name)返回最后出现的name、value。通常情况这也是唯一的name、value。如果没有值，那么header(name)将返回null。如果想读取字段对应的所有值，使用headers(name)会返回一个list。<br>为了获取所有的Header，Headers类支持按index访问。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">private final OkHttpClient client = new OkHttpClient();</span><br><span class="line"> </span><br><span class="line">public void run() throws Exception &#123;</span><br><span class="line">    Request request = new Request.Builder()</span><br><span class="line">        .url(&quot;https://api.github.com/repos/square/okhttp/issues&quot;)</span><br><span class="line">        .header(&quot;User-Agent&quot;, &quot;OkHttp Headers.java&quot;)</span><br><span class="line">        .addHeader(&quot;Accept&quot;, &quot;application/json; q=0.5&quot;)</span><br><span class="line">        .addHeader(&quot;Accept&quot;, &quot;application/vnd.github.v3+json&quot;)</span><br><span class="line">        .build();</span><br><span class="line"> </span><br><span class="line">    Response response = client.newCall(request).execute();</span><br><span class="line">    if (!response.isSuccessful()) throw new IOException(&quot;Unexpected code &quot; + response);</span><br><span class="line"> </span><br><span class="line">    System.out.println(&quot;Server: &quot; + response.header(&quot;Server&quot;));</span><br><span class="line">    System.out.println(&quot;Date: &quot; + response.header(&quot;Date&quot;));</span><br><span class="line">    System.out.println(&quot;Vary: &quot; + response.headers(&quot;Vary&quot;));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="Post方式提交String"><a href="#Post方式提交String" class="headerlink" title="Post方式提交String"></a>Post方式提交String</h2><p>使用HTTP POST提交请求到服务。这个例子提交了一个markdown文档到web服务，以HTML方式渲染markdown。因为整个请求体都在内存中，因此避免使用此api提交大文档（大于1MB）。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">public static final MediaType MEDIA_TYPE_MARKDOWN</span><br><span class="line">  = MediaType.parse(&quot;text/x-markdown; charset=utf-8&quot;);</span><br><span class="line"> </span><br><span class="line">private final OkHttpClient client = new OkHttpClient();</span><br><span class="line"> </span><br><span class="line">public void run() throws Exception &#123;</span><br><span class="line">    String postBody = &quot;&quot;</span><br><span class="line">        + &quot;Releases\n&quot;</span><br><span class="line">        + &quot;--------\n&quot;</span><br><span class="line">        + &quot;\n&quot;</span><br><span class="line">        + &quot; * _1.0_ May 6, 2013\n&quot;</span><br><span class="line">        + &quot; * _1.1_ June 15, 2013\n&quot;</span><br><span class="line">        + &quot; * _1.2_ August 11, 2013\n&quot;;</span><br><span class="line"> </span><br><span class="line">    Request request = new Request.Builder()</span><br><span class="line">        .url(&quot;https://api.github.com/markdown/raw&quot;)</span><br><span class="line">        .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, postBody))</span><br><span class="line">        .build();</span><br><span class="line"> </span><br><span class="line">    Response response = client.newCall(request).execute();</span><br><span class="line">    if (!response.isSuccessful()) throw new IOException(&quot;Unexpected code &quot; + response);</span><br><span class="line"> </span><br><span class="line">    System.out.println(response.body().string());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="Post方式提交流"><a href="#Post方式提交流" class="headerlink" title="Post方式提交流"></a>Post方式提交流</h2><p>以流的方式POST提交请求体。请求体的内容由流写入产生。这个例子是流直接写入Okio的BufferedSink。你的程序可能会使用OutputStream，你可以使用BufferedSink.outputStream()来获取。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br></pre></td><td class="code"><pre><span class="line">public static final MediaType MEDIA_TYPE_MARKDOWN</span><br><span class="line">      = MediaType.parse(&quot;text/x-markdown; charset=utf-8&quot;);</span><br><span class="line"> </span><br><span class="line">private final OkHttpClient client = new OkHttpClient();</span><br><span class="line"> </span><br><span class="line">public void run() throws Exception &#123;</span><br><span class="line">    RequestBody requestBody = new RequestBody() &#123;</span><br><span class="line">      @Override public MediaType contentType() &#123;</span><br><span class="line">        return MEDIA_TYPE_MARKDOWN;</span><br><span class="line">      &#125;</span><br><span class="line"> </span><br><span class="line">      @Override public void writeTo(BufferedSink sink) throws IOException &#123;</span><br><span class="line">        sink.writeUtf8(&quot;Numbers\n&quot;);</span><br><span class="line">        sink.writeUtf8(&quot;-------\n&quot;);</span><br><span class="line">        for (int i = 2; i &lt;= 997; i++) &#123;</span><br><span class="line">          sink.writeUtf8(String.format(&quot; * %s = %s\n&quot;, i, factor(i)));</span><br><span class="line">        &#125;</span><br><span class="line">      &#125;</span><br><span class="line"> </span><br><span class="line">      private String factor(int n) &#123;</span><br><span class="line">        for (int i = 2; i &lt; n; i++) &#123;</span><br><span class="line">          int x = n / i;</span><br><span class="line">          if (x * i == n) return factor(x) + &quot; × &quot; + i;</span><br><span class="line">        &#125;</span><br><span class="line">        return Integer.toString(n);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;;</span><br><span class="line"> </span><br><span class="line">    Request request = new Request.Builder()</span><br><span class="line">        .url(&quot;https://api.github.com/markdown/raw&quot;)</span><br><span class="line">        .post(requestBody)</span><br><span class="line">        .build();</span><br><span class="line"> </span><br><span class="line">    Response response = client.newCall(request).execute();</span><br><span class="line">    if (!response.isSuccessful()) throw new IOException(&quot;Unexpected code &quot; + response);</span><br><span class="line"> </span><br><span class="line">    System.out.println(response.body().string());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="Post方式提交文件"><a href="#Post方式提交文件" class="headerlink" title="Post方式提交文件"></a>Post方式提交文件</h2><p>以文件作为请求体是十分简单的。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line">public static final MediaType MEDIA_TYPE_MARKDOWN</span><br><span class="line">  = MediaType.parse(&quot;text/x-markdown; charset=utf-8&quot;);</span><br><span class="line"> </span><br><span class="line">private final OkHttpClient client = new OkHttpClient();</span><br><span class="line"> </span><br><span class="line">public void run() throws Exception &#123;</span><br><span class="line">    File file = new File(&quot;README.md&quot;);</span><br><span class="line"> </span><br><span class="line">    Request request = new Request.Builder()</span><br><span class="line">        .url(&quot;https://api.github.com/markdown/raw&quot;)</span><br><span class="line">        .post(RequestBody.create(MEDIA_TYPE_MARKDOWN, file))</span><br><span class="line">        .build();</span><br><span class="line"> </span><br><span class="line">    Response response = client.newCall(request).execute();</span><br><span class="line">    if (!response.isSuccessful()) throw new IOException(&quot;Unexpected code &quot; + response);</span><br><span class="line"> </span><br><span class="line">    System.out.println(response.body().string());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="Post方式提交表单"><a href="#Post方式提交表单" class="headerlink" title="Post方式提交表单"></a>Post方式提交表单</h2><p>使用FormEncodingBuilder来构建和HTML<form>标签相同效果的请求体。键值对将使用一种HTML兼容形式的URL编码来进行编码。</form></p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line">private final OkHttpClient client = new OkHttpClient();</span><br><span class="line"> </span><br><span class="line">public void run() throws Exception &#123;</span><br><span class="line">    RequestBody formBody = new FormEncodingBuilder()</span><br><span class="line">        .add(&quot;search&quot;, &quot;Jurassic Park&quot;)</span><br><span class="line">        .build();</span><br><span class="line">    Request request = new Request.Builder()</span><br><span class="line">        .url(&quot;https://en.wikipedia.org/w/index.php&quot;)</span><br><span class="line">        .post(formBody)</span><br><span class="line">        .build();</span><br><span class="line"> </span><br><span class="line">    Response response = client.newCall(request).execute();</span><br><span class="line">    if (!response.isSuccessful()) throw new IOException(&quot;Unexpected code &quot; + response);</span><br><span class="line"> </span><br><span class="line">    System.out.println(response.body().string());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="Post方式提交分块请求"><a href="#Post方式提交分块请求" class="headerlink" title="Post方式提交分块请求"></a>Post方式提交分块请求</h2><p>MultipartBuilder可以构建复杂的请求体，与HTML文件上传形式兼容。多块请求体中每块请求都是一个请求体，可以定义自己的请求头。这些请求头可以用来描述这块请求，例如他的Content-Disposition。如果Content-Length和Content-Type可用的话，他们会被自动添加到请求头中。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">private static final String IMGUR_CLIENT_ID = &quot;...&quot;;</span><br><span class="line">private static final MediaType MEDIA_TYPE_PNG = MediaType.parse(&quot;image/png&quot;);</span><br><span class="line"> </span><br><span class="line">private final OkHttpClient client = new OkHttpClient();</span><br><span class="line"> </span><br><span class="line">public void run() throws Exception &#123;</span><br><span class="line">    // Use the imgur image upload API as documented at https://api.imgur.com/endpoints/image</span><br><span class="line">    RequestBody requestBody = new MultipartBuilder()</span><br><span class="line">        .type(MultipartBuilder.FORM)</span><br><span class="line">        .addPart(</span><br><span class="line">            Headers.of(&quot;Content-Disposition&quot;, &quot;form-data; name=\&quot;title\&quot;&quot;),</span><br><span class="line">            RequestBody.create(null, &quot;Square Logo&quot;))</span><br><span class="line">        .addPart(</span><br><span class="line">            Headers.of(&quot;Content-Disposition&quot;, &quot;form-data; name=\&quot;image\&quot;&quot;),</span><br><span class="line">            RequestBody.create(MEDIA_TYPE_PNG, new File(&quot;website/static/logo-square.png&quot;)))</span><br><span class="line">        .build();</span><br><span class="line"> </span><br><span class="line">    Request request = new Request.Builder()</span><br><span class="line">        .header(&quot;Authorization&quot;, &quot;Client-ID &quot; + IMGUR_CLIENT_ID)</span><br><span class="line">        .url(&quot;https://api.imgur.com/3/image&quot;)</span><br><span class="line">        .post(requestBody)</span><br><span class="line">        .build();</span><br><span class="line"> </span><br><span class="line">    Response response = client.newCall(request).execute();</span><br><span class="line">    if (!response.isSuccessful()) throw new IOException(&quot;Unexpected code &quot; + response);</span><br><span class="line"> </span><br><span class="line">    System.out.println(response.body().string());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="使用Gson来解析JSON响应"><a href="#使用Gson来解析JSON响应" class="headerlink" title="使用Gson来解析JSON响应"></a>使用Gson来解析JSON响应</h2><p>Gson是一个在JSON和Java对象之间转换非常方便的api。这里我们用Gson来解析Github API的JSON响应。<br>注意：ResponseBody.charStream()使用响应头Content-Type指定的字符集来解析响应体。默认是UTF-8。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line">private final OkHttpClient client = new OkHttpClient();</span><br><span class="line">private final Gson gson = new Gson();</span><br><span class="line"> </span><br><span class="line">public void run() throws Exception &#123;</span><br><span class="line">    Request request = new Request.Builder()</span><br><span class="line">        .url(&quot;https://api.github.com/gists/c2a7c39532239ff261be&quot;)</span><br><span class="line">        .build();</span><br><span class="line">    Response response = client.newCall(request).execute();</span><br><span class="line">    if (!response.isSuccessful()) throw new IOException(&quot;Unexpected code &quot; + response);</span><br><span class="line"> </span><br><span class="line">    Gist gist = gson.fromJson(response.body().charStream(), Gist.class);</span><br><span class="line">    for (Map.Entry&lt;String, GistFile&gt; entry : gist.files.entrySet()) &#123;</span><br><span class="line">      System.out.println(entry.getKey());</span><br><span class="line">      System.out.println(entry.getValue().content);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line">static class Gist &#123;</span><br><span class="line">    Map&lt;String, GistFile&gt; files;</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line">static class GistFile &#123;</span><br><span class="line">    String content;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="响应缓存"><a href="#响应缓存" class="headerlink" title="响应缓存"></a>响应缓存</h2><p>为了缓存响应，你需要一个你可以读写的缓存目录，和缓存大小的限制。这个缓存目录应该是私有的，不信任的程序应不能读取缓存内容。<br>一个缓存目录同时拥有多个缓存访问是错误的。大多数程序只需要调用一次new OkHttp()，在第一次调用时配置好缓存，然后其他地方只需要调用这个实例就可以了。否则两个缓存示例互相干扰，破坏响应缓存，而且有可能会导致程序崩溃。<br>响应缓存使用HTTP头作为配置。你可以在请求头中添加Cache-Control: max-stale=3600 ,OkHttp缓存会支持。你的服务通过响应头确定响应缓存多长时间，例如使用Cache-Control: max-age=9600。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br></pre></td><td class="code"><pre><span class="line">private final OkHttpClient client;</span><br><span class="line"> </span><br><span class="line">public CacheResponse(File cacheDirectory) throws Exception &#123;</span><br><span class="line">    int cacheSize = 10 * 1024 * 1024; // 10 MiB</span><br><span class="line">    Cache cache = new Cache(cacheDirectory, cacheSize);</span><br><span class="line"> </span><br><span class="line">    client = new OkHttpClient();</span><br><span class="line">    client.setCache(cache);</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line">public void run() throws Exception &#123;</span><br><span class="line">    Request request = new Request.Builder()</span><br><span class="line">        .url(&quot;http://publicobject.com/helloworld.txt&quot;)</span><br><span class="line">        .build();</span><br><span class="line"> </span><br><span class="line">    Response response1 = client.newCall(request).execute();</span><br><span class="line">    if (!response1.isSuccessful()) throw new IOException(&quot;Unexpected code &quot; + response1);</span><br><span class="line"> </span><br><span class="line">    String response1Body = response1.body().string();</span><br><span class="line">    System.out.println(&quot;Response 1 response:          &quot; + response1);</span><br><span class="line">    System.out.println(&quot;Response 1 cache response:    &quot; + response1.cacheResponse());</span><br><span class="line">    System.out.println(&quot;Response 1 network response:  &quot; + response1.networkResponse());</span><br><span class="line"> </span><br><span class="line">    Response response2 = client.newCall(request).execute();</span><br><span class="line">    if (!response2.isSuccessful()) throw new IOException(&quot;Unexpected code &quot; + response2);</span><br><span class="line"> </span><br><span class="line">    String response2Body = response2.body().string();</span><br><span class="line">    System.out.println(&quot;Response 2 response:          &quot; + response2);</span><br><span class="line">    System.out.println(&quot;Response 2 cache response:    &quot; + response2.cacheResponse());</span><br><span class="line">    System.out.println(&quot;Response 2 network response:  &quot; + response2.networkResponse());</span><br><span class="line"> </span><br><span class="line">    System.out.println(&quot;Response 2 equals Response 1? &quot; + response1Body.equals(response2Body));</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="扩展"><a href="#扩展" class="headerlink" title="扩展"></a>扩展</h2><p>在这一节还提到了下面一句：<br>There are cache headers to force a cached response, force a network response, or force the network response to be validated with a conditional GET.</p>
<p>我不是很懂cache，平时用到的也不多，所以把Google在Android Developers一段相关的解析放到这里吧。</p>
<h2 id="Force-a-Network-Response"><a href="#Force-a-Network-Response" class="headerlink" title="Force a Network Response"></a>Force a Network Response</h2><p>In some situations, such as after a user clicks a ‘refresh’ button, it may be necessary to skip the cache, and fetch data directly from the server. To force a full refresh, add the no-cache directive:</p>
<blockquote>
<p>connection.addRequestProperty(“Cache-Control”, “no-cache”);</p>
</blockquote>
<p>If it is only necessary to force a cached response to be validated by the server, use the more efficient max-age=0 instead:</p>
<blockquote>
<p>connection.addRequestProperty(“Cache-Control”, “max-age=0”);</p>
</blockquote>
<p>##Force a Cache Response<br>Sometimes you’ll want to show resources if they are available immediately, but not otherwise. This can be used so your application can show something while waiting for the latest data to be downloaded. To restrict a request to locally-cached resources, add the only-if-cached directive:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">try &#123;</span><br><span class="line">     connection.addRequestProperty(&quot;Cache-Control&quot;, &quot;only-if-cached&quot;);</span><br><span class="line">     InputStream cached = connection.getInputStream();</span><br><span class="line">     // the resource was cached! show it</span><br><span class="line">  catch (FileNotFoundException e) &#123;</span><br><span class="line">     // the resource was not cached</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>This technique works even better in situations where a stale response is better than no response. To permit stale cached responses, use the max-stale directive with the maximum staleness in seconds:</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">int maxStale = 60 * 60 * 24 * 28; // tolerate 4-weeks staleconnection.addRequestProperty(&quot;Cache-Control&quot;, &quot;max-stale=&quot; + maxStale);</span><br></pre></td></tr></table></figure>
<p>以上信息来自：<a href="http://developer.android.com/reference/android/net/http/HttpResponseCache.html" target="_blank" rel="noopener">HttpResponseCache - Android SDK | Android Developers</a></p>
<h2 id="取消一个Call"><a href="#取消一个Call" class="headerlink" title="取消一个Call"></a>取消一个Call</h2><p>使用Call.cancel()可以立即停止掉一个正在执行的call。如果一个线程正在写请求或者读响应，将会引发IOException。当call没有必要的时候，使用这个api可以节约网络资源。例如当用户离开一个应用时。不管同步还是异步的call都可以取消。<br>你可以通过tags来同时取消多个请求。当你构建一请求时，使用RequestBuilder.tag(tag)来分配一个标签。之后你就可以用OkHttpClient.cancel(tag)来取消所有带有这个tag的call。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br></pre></td><td class="code"><pre><span class="line">private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);</span><br><span class="line">private final OkHttpClient client = new OkHttpClient();</span><br><span class="line"> </span><br><span class="line">public void run() throws Exception &#123;</span><br><span class="line">    Request request = new Request.Builder()</span><br><span class="line">        .url(&quot;http://httpbin.org/delay/2&quot;) // This URL is served with a 2 second delay.</span><br><span class="line">        .build();</span><br><span class="line"> </span><br><span class="line">    final long startNanos = System.nanoTime();</span><br><span class="line">    final Call call = client.newCall(request);</span><br><span class="line"> </span><br><span class="line">    // Schedule a job to cancel the call in 1 second.</span><br><span class="line">    executor.schedule(new Runnable() &#123;</span><br><span class="line">      @Override public void run() &#123;</span><br><span class="line">        System.out.printf(&quot;%.2f Canceling call.%n&quot;, (System.nanoTime() - startNanos) / 1e9f);</span><br><span class="line">        call.cancel();</span><br><span class="line">        System.out.printf(&quot;%.2f Canceled call.%n&quot;, (System.nanoTime() - startNanos) / 1e9f);</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;, 1, TimeUnit.SECONDS);</span><br><span class="line"> </span><br><span class="line">    try &#123;</span><br><span class="line">      System.out.printf(&quot;%.2f Executing call.%n&quot;, (System.nanoTime() - startNanos) / 1e9f);</span><br><span class="line">      Response response = call.execute();</span><br><span class="line">      System.out.printf(&quot;%.2f Call was expected to fail, but completed: %s%n&quot;,</span><br><span class="line">          (System.nanoTime() - startNanos) / 1e9f, response);</span><br><span class="line">    &#125; catch (IOException e) &#123;</span><br><span class="line">      System.out.printf(&quot;%.2f Call failed as expected: %s%n&quot;,</span><br><span class="line">          (System.nanoTime() - startNanos) / 1e9f, e);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="超时"><a href="#超时" class="headerlink" title="超时"></a>超时</h2><p>没有响应时使用超时结束call。没有响应的原因可能是客户点链接问题、服务器可用性问题或者这之间的其他东西。OkHttp支持连接，读取和写入超时</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line">private final OkHttpClient client;</span><br><span class="line"> </span><br><span class="line">public ConfigureTimeouts() throws Exception &#123;</span><br><span class="line">    client = new OkHttpClient();</span><br><span class="line">    client.setConnectTimeout(10, TimeUnit.SECONDS);</span><br><span class="line">    client.setWriteTimeout(10, TimeUnit.SECONDS);</span><br><span class="line">    client.setReadTimeout(30, TimeUnit.SECONDS);</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line">public void run() throws Exception &#123;</span><br><span class="line">    Request request = new Request.Builder()</span><br><span class="line">        .url(&quot;http://httpbin.org/delay/2&quot;) // This URL is served with a 2 second delay.</span><br><span class="line">        .build();</span><br><span class="line"> </span><br><span class="line">    Response response = client.newCall(request).execute();</span><br><span class="line">    System.out.println(&quot;Response completed: &quot; + response);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="每个call的配置"><a href="#每个call的配置" class="headerlink" title="每个call的配置"></a>每个call的配置</h2><p>使用OkHttpClient，所有的HTTP Client配置包括代理设置、超时设置、缓存设置。当你需要为单个call改变配置的时候，clone 一个 OkHttpClient。这个api将会返回一个浅拷贝（shallow copy），你可以用来单独自定义。下面的例子中，我们让一个请求是500ms的超时、另一个是3000ms的超时。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">private final OkHttpClient client = new OkHttpClient();</span><br><span class="line"> </span><br><span class="line">public void run() throws Exception &#123;</span><br><span class="line">    Request request = new Request.Builder()</span><br><span class="line">        .url(&quot;http://httpbin.org/delay/1&quot;) // This URL is served with a 1 second delay.</span><br><span class="line">        .build();</span><br><span class="line"> </span><br><span class="line">    try &#123;</span><br><span class="line">      Response response = client.clone() // Clone to make a customized OkHttp for this request.</span><br><span class="line">          .setReadTimeout(500, TimeUnit.MILLISECONDS)</span><br><span class="line">          .newCall(request)</span><br><span class="line">          .execute();</span><br><span class="line">      System.out.println(&quot;Response 1 succeeded: &quot; + response);</span><br><span class="line">    &#125; catch (IOException e) &#123;</span><br><span class="line">      System.out.println(&quot;Response 1 failed: &quot; + e);</span><br><span class="line">    &#125;</span><br><span class="line"> </span><br><span class="line">    try &#123;</span><br><span class="line">      Response response = client.clone() // Clone to make a customized OkHttp for this request.</span><br><span class="line">          .setReadTimeout(3000, TimeUnit.MILLISECONDS)</span><br><span class="line">          .newCall(request)</span><br><span class="line">          .execute();</span><br><span class="line">      System.out.println(&quot;Response 2 succeeded: &quot; + response);</span><br><span class="line">    &#125; catch (IOException e) &#123;</span><br><span class="line">      System.out.println(&quot;Response 2 failed: &quot; + e);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="处理验证"><a href="#处理验证" class="headerlink" title="处理验证"></a>处理验证</h2><p>这部分和HTTP AUTH有关。<br>相关资料：<a href="http://blog.csdn.net/wwwsq/article/details/7255062" target="_blank" rel="noopener">HTTP AUTH 那些事 - 王绍全的博客 - 博客频道 - CSDN.NET</a></p>
<p>OkHttp会自动重试未验证的请求。当响应是401 Not Authorized时，Authenticator会被要求提供证书。Authenticator的实现中需要建立一个新的包含证书的请求。如果没有证书可用，返回null来跳过尝试。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">public List&lt;Challenge&gt; challenges()</span><br><span class="line">Returns the authorization challenges appropriate for this response&apos;s code. </span><br><span class="line">If the response code is 401 unauthorized, </span><br><span class="line">this returns the &quot;WWW-Authenticate&quot; challenges.</span><br><span class="line">If the response code is 407 proxy unauthorized, this returns the &quot;Proxy-Authenticate&quot; challenges.</span><br><span class="line">Otherwise this returns an empty list of challenges.</span><br></pre></td></tr></table></figure>
<p>当需要实现一个Basic challenge， 使用Credentials.basic(username, password)来编码请求头。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br></pre></td><td class="code"><pre><span class="line">private final OkHttpClient client = new OkHttpClient();</span><br><span class="line"> </span><br><span class="line">public void run() throws Exception &#123;</span><br><span class="line">    client.setAuthenticator(new Authenticator() &#123;</span><br><span class="line">      @Override public Request authenticate(Proxy proxy, Response response) &#123;</span><br><span class="line">        System.out.println(&quot;Authenticating for response: &quot; + response);</span><br><span class="line">        System.out.println(&quot;Challenges: &quot; + response.challenges());</span><br><span class="line">        String credential = Credentials.basic(&quot;jesse&quot;, &quot;password1&quot;);</span><br><span class="line">        return response.request().newBuilder()</span><br><span class="line">            .header(&quot;Authorization&quot;, credential)</span><br><span class="line">            .build();</span><br><span class="line">      &#125;</span><br><span class="line"> </span><br><span class="line">      @Override public Request authenticateProxy(Proxy proxy, Response response) &#123;</span><br><span class="line">        return null; // Null indicates no attempt to authenticate.</span><br><span class="line">      &#125;</span><br><span class="line">    &#125;);</span><br><span class="line"> </span><br><span class="line">    Request request = new Request.Builder()</span><br><span class="line">        .url(&quot;http://publicobject.com/secrets/hellosecret.txt&quot;)</span><br><span class="line">        .build();</span><br><span class="line"> </span><br><span class="line">    Response response = client.newCall(request).execute();</span><br><span class="line">    if (!response.isSuccessful()) throw new IOException(&quot;Unexpected code &quot; + response);</span><br><span class="line"> </span><br><span class="line">    System.out.println(response.body().string());</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>转自 <a href="http://www.cnblogs.com/ct2011/p/4001708.html" target="_blank" rel="noopener">OkHttp使用介绍</a> 同时整合了 <a href="http://www.cnblogs.com/ct2011/p/3997368.html" target="_blank" rel="noopener">OkHttp使用进阶</a> 这篇文章以及其中的评论。</p>

                
<p class="pink-link-context">
    <a href="/2016/05/10/iosdev/" rel="next" title="ios开发笔记">
    上一篇：ios开发笔记
  </a>
</p>



<p class="pink-link-context">
    <a href="/2016/05/09/gowaywenzi/" rel="next" title="教你几招，蚊子一个夏天不敢进你的房间！！">
    下一篇：教你几招，蚊子一个夏天不敢进你的房间！！
  </a>
</p>


            </div>
			
        </div>
    </div>
</article>




    <section id="comment">
        <div class="card">
            <div class="card-content">
                <!-- Duoshuo Comment BEGIN -->
                <div class="ds-thread" data-thread-key="2016/05/09/okhttphelp/" data-title="OkHttp使用教程" data-url="http://uuxia.cn/2016/05/09/okhttphelp/"></div>

                <script type="text/javascript">
                    console.log(document.querySelector('.ds-thread'));
                    var duoshuoQuery = {
                        short_name: 'uuxia'
                    };
                    (function() {
                        var ds = document.createElement('script');
                        ds.type = 'text/javascript';
                        ds.async = true;
                        ds.src = (document.location.protocol == 'https:'
                            ? 'https:'
                            : 'http:') + '//static.duoshuo.com/embed.js';
                        ds.charset = 'UTF-8';
                        (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(ds);
                    })();
                </script>
                <!-- Duoshuo Comment END -->
            </div>
        </div>
    </section>




</div>

        <div class="fixed-action-btn float-sitemap">
    <a class="btn-floating btn-large pink">
      <i class="fa fa-caret-square-o-up"></i>
    </a>
    <ul>
      <li><a class="btn-return-top btn-floating waves-effect green" title="回到顶部"><i class="fa fa-arrow-circle-o-up"></i></a></li>
      <li><a class="btn-floating waves-effect button-collapse yellow darken-1"  data-activates="main-menu" title="菜单"><i class="fa fa-navicon"></i></a></li>
    </ul>
  </div>

    </main>
    <footer class="page-footer indigo darken-1">
    
    <div class="footer-container container">
        <div class="row">
            
            <div class="social-group col m4 s12">
                <h5 class="white-text">社交</h5>
                
                    <a class="social-link" href="http://weibo.com/" target="_blank">
                        <i class="fa fa-2x fa-weibo"></i>
                    </a>
                
                    <a class="social-link" href="https://github.com/xxl6097" target="_blank">
                        <i class="fa fa-2x fa-github"></i>
                    </a>
                
                    <a class="social-link" href="/atom.xml" target="_blank">
                        <i class="fa fa-2x fa-rss"></i>
                    </a>
                
                
    <script async src="//dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js">
    </script>
    <div class="site-visitors-container white-text">
        <span>
            <i class="fa fa-user"></i>
            <span class="busuanzi-value" id="busuanzi_value_site_uv"></span>
        </span>
        <span>&nbsp;|&nbsp;</span>
        <span>
            <i class="fa fa-eye"></i>
            <span class="busuanzi-value" id="busuanzi_value_site_pv"></span>
        </span>
    </div>


            </div>
            

            
            <div class="col m8 s12">
                <h5 class="white-text">友情链接</h5>
                
                    <a class="social-link" href="http://raytaylorlin.com/" target="_blank">raytaylorism主题作者的技术博客</a>
                
                    <a class="social-link" href="https://github.com/xxl6097" target="_blank">Github地址（测试友情链接）</a>
                
            </div>
            
        </div>
    </div>
    
    <div style="width:300px;margin:0 auto; padding:20px 0;">
        <a target="_blank" href="https://www.beian.gov.cn/portal/registerSystemInfo?recordcode=44030502001748" style="display:inline-block;text-decoration:none;height:20px;line-height:20px;"><img src="" style="float:left;"/><p style="float:left;height:20px;line-height:20px;margin: 0px 0px 0px 5px; color:#939393;">粤公网安备 44030502001748号</p></a>
    </div>
    <div class="footer-copyright pink-link-context">
        <div class="container">
            © 2018 uuxia.cn, All rights reserved.
            <p class="right" style="margin-top: 0;">本博客由 <a href="https://hexo.io">Hexo</a> 强力驱动 | 主题 <a href="https://github.com/raytaylorlin/hexo-theme-raytaylorism">raytaylorism</a></p>
        </div>
    </div>

</footer>


    <noscript>
    <div class="noscript">
        <p class="center-align">当前网速较慢或者你使用的浏览器不支持博客特定功能，请尝试刷新或换用Chrome、Firefox等现代浏览器</p>
    </div>
</noscript>
<div class="noscript">
    <p class="center-align">当前网速较慢或者你使用的浏览器不支持博客特定功能，请尝试刷新或换用Chrome、Firefox等现代浏览器</p>
</div>


<script src="/js/jquery.min.js"></script>
<script src="/js/materialize.min.js"></script>

<script>
    (function($) {
        $(document).ready(function() {
            // 隐藏禁用javascript（针对微信内置浏览器）的提示
            $('.noscript').hide();

            // 图片缩放效果
            var $imgs = $('img').not('.slider-image').not('.avatar-image').not('.carousel-image').not('.card-cover-image').not('.qrcode');

            // 给图片加上点击放大效果（materialbox插件）
            $imgs.addClass('materialboxed').each(function(i, el) {
                $(this).attr('data-caption', $(this).attr('alt') || ' ');
            }).materialbox();

            // 优化表格的显示
            $('table').each(function() {
                var $table = $(this);
                // 除去多行代码的情况
                if ($table.find('pre').length == 0) {
                    $table.addClass('responsive-table striped bordered');
                }
            });

            // 首页幻灯片
            $('.slider').slider({indicators: true, full_width: true, interval: 8000});

            $(".button-collapse").sideNav();
            $(".category-menu").sideNav();

            // 针对gallery post
            $('.carousel').carousel({full_width: true});
            $('.carousel-control.prev').click(function() {
                $('.carousel').carousel('prev');
            });
            $('.carousel-control.next').click(function() {
                $('.carousel').carousel('next');
            });

            // 文章目录
            $('article').not('.simple-article').find('h1').add('h2').add('h3').add('h4').add('h5').add('h6').scrollSpy();

            // 目录随屏幕滚动（防止目录过长越过footer）
            var $toc = $('.toc');
            var scrollTargetTop = 0;
            $(window).scroll(function() {
                var $activeLink = $toc.find('a.active.section');
                if ($(window).scrollTop() < 100) {
                    scrollTargetTop = 0;
                } else {
                    if ($activeLink[0]) {
                        scrollTargetTop = $activeLink.offset().top - $toc.offset().top;
                    }
                }
                $toc.css('top', '-' + scrollTargetTop + 'px');
            });

            // 修正文章目录的left-border颜色
            var color = $('.table-of-contents-text').css('color');
            $('.table-of-contents-link').css('border-left-color', color);

            // 针对移动端做的优化：FAB按钮点击一下收回
            if (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
                $('.fixed-action-btn').addClass('click-to-toggle');
            }
            // 回到顶部
            $('.btn-return-top').click(function() {
                $('body, html').animate({
                    scrollTop: 0
                }, 500);
            });

            // 重置读书页面的Tab标签页的颜色
            $('li.tab a').hover(function() {
                $(this).toggleClass('text-lighten-4');
            });
            $('.indicator').addClass('pink lighten-2');

            
            // 添加new标签
            $('.menu-reading, .menu-about').append('<span class="new badge pink"></span>');
            

            // 搜索功能
            $('.modal-trigger').leanModal({
                // 打开搜索框时自动聚焦
                ready: function() {
                    if ($('#search').is(":visible")) {
                        $('#search-input').focus();
                    }
                }
            });
            var searchXml = "search.xml";
            if (searchXml.length == 0) {
             	searchXml = "search.xml";
            }
            var searchPath = "/" + searchXml;
            initSearch(searchPath, 'search-input', 'search-result');
        });

        // 初始化搜索与匹配函数
        var initSearch = function(path, search_id, content_id) {
            'use strict';
            $.ajax({
                url: path,
                dataType: "xml",
                success: function(xmlResponse) {
                    // get the contents from search data
                    var datas = $("entry", xmlResponse).map(function() {
                        return {
                            title: $("title", this).text(),
                            content: $("content", this).text(),
                            url: $("url", this).text()
                        };
                    }).get();
                    var $input = document.getElementById(search_id);
                    var $resultContent = document.getElementById(content_id);
                    $input.addEventListener('input', function() {
                        var str = '<ul class=\"search-result-list\">';
                        var keywords = this.value.trim().toLowerCase().split(/[\s\-]+/);
                        $resultContent.innerHTML = "";
                        if (this.value.trim().length <= 0) {
                            return;
                        }
                        // perform local searching
                        datas.forEach(function(data) {
                            var isMatch = true;
                            var content_index = [];
                            var data_title = data.title.trim().toLowerCase();
                            var data_content = data.content.trim().replace(/<[^>]+>/g, "").toLowerCase();
                            var data_url = data.url;
                            var index_title = -1;
                            var index_content = -1;
                            var first_occur = -1;
                            // only match artiles with not empty titles and contents
                            if (data_title != '' && data_content != '') {
                                keywords.forEach(function(keyword, i) {
                                    index_title = data_title.indexOf(keyword);
                                    index_content = data_content.indexOf(keyword);
                                    if (index_title < 0 && index_content < 0) {
                                        isMatch = false;
                                    } else {
                                        if (index_content < 0) {
                                            index_content = 0;
                                        }
                                        if (i == 0) {
                                            first_occur = index_content;
                                        }
                                    }
                                });
                            }
                            // show search results
                            if (isMatch) {
                                keywords.forEach(function(keyword) {
                                    var regS = new RegExp(keyword, "gi");
                                    data_title = data_title.replace(regS, "<span class=\"search-keyword pink lighten-2\">" + keyword + "</span>");
                                });

                                str += "<li><a href='" + data_url + "' class='search-result-title'>" + data_title + "</a>";
                                var content = data.content.trim().replace(/<[^>]+>/g, "");
                                if (first_occur >= 0) {
                                    // cut out 100 characters
                                    var start = first_occur - 20;
                                    var end = first_occur + 80;
                                    if (start < 0) {
                                        start = 0;
                                    }
                                    if (start == 0) {
                                        end = 100;
                                    }
                                    if (end > content.length) {
                                        end = content.length;
                                    }
                                    var match_content = content.substring(start, end);
                                    // highlight all keywords
                                    keywords.forEach(function(keyword) {
                                        var regS = new RegExp(keyword, "gi");
                                        match_content = match_content.replace(regS, "<span class=\"search-keyword pink lighten-2\">" + keyword + "</span>");
                                    });

                                    str += "<p class=\"search-result\">..." + match_content + "...</p>"
                                }
                                str += "</li>";
                            }
                        });
                        str += "</ul>";
                        $resultContent.innerHTML = str;
                    });
                }
            });
        }
    })(jQuery);
</script>


<script src="/js/prettify.js"></script>
<script type="text/javascript">
    $(document).ready(function() {
        $("pre").addClass("prettyprint");
        prettyPrint();
    });
</script>




<script type="text/javascript" src="http://tajs.qq.com/stats?sId=56133145" charset="UTF-8"></script>



<script type="text/x-mathjax-config">
MathJax.Hub.Config({
  tex2jax: {inlineMath: [['$','$'], ['\\(','\\)']]}
});
</script>
<script type="text/javascript" async
  src="//cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-MML-AM_CHTML">
</script>



</body>
</html>
